######################################################################
# DBI object mapping to the *ep_user* table
######################################################################
package EP::Common::DBI::User;

use strict;
use base qw( EP::Common::DBI );

use EP::Common::DBI::Folder;
use EP::Common::DBI::Action;
use Crypt::PasswdMD5;

EP::Common::DBI::User->table('ep_user');
EP::Common::DBI::User->sequence('ep_user_seq');

EP::Common::DBI::User->columns ( Primary   => qw( id ) );
EP::Common::DBI::User->columns ( Essential => qw( username first_name last_name session_only last_folder last_root_dataset last_action last_cluster_selection ) );
EP::Common::DBI::User->columns ( Others    => qw( password salt institute department address telephone email
                                                  user_level visualization_format show_analysis_history show_context_help epc_size_state created last_login ) );

EP::Common::DBI::User->add_trigger( before_create => \&_before_create );

EP::Common::DBI::User->has_a( last_folder => 'EP::Common::DBI::Folder',
                              inflate => sub { my $id = shift; EP::Common::DBI::Folder->retrieve($id); } );
EP::Common::DBI::User->has_a( last_action => 'EP::Common::DBI::Action',
                              inflate => sub { my $id = shift; EP::Common::DBI::Action->retrieve($id); } );
EP::Common::DBI::User->has_a( last_root_dataset => 'EP::Common::DBI::Dataset',
                              inflate => sub { my $id = shift; EP::Common::DBI::Dataset->retrieve($id); } );

EP::Common::DBI::User->has_many( folders          => 'EP::Common::DBI::Folder' );
EP::Common::DBI::User->has_many( admin_of_groups  => 'EP::Common::DBI::Group'  );
EP::Common::DBI::User->has_many( member_of_groups => [ 'EP::Common::DBI::User_Group' => 'ep_group' ] );

EP::Common::DBI::User->autoupdate(1);

# Sub: create
#  Overrides the default *create* method to make sure that the user folder is created at the same time the user is.
sub
create
    {
    my $self = shift;
    my ($params) = @_;

    my ($user) = $self->do_transaction
        (
        sub {
            my ($root_folder) = EP::Common::DBI::Folder->search({ name => 'root' });

            my $user = $self->SUPER::create( $params);
            my $folder = EP::Common::DBI::Folder->SUPER::create
                (
                    { name          => $params->{username}
                    , location      => $params->{username}
                    , parent        => $root_folder
                    , owner         => $user
                    , group_write   => 0
                    , group_read    => 1
                    , other_read    => 0
                    }
                );

            if ( $user and $folder )
                {
                EP::Common::DBI::Folder->_create_physical_directory( $params->{username} );
            }

            $user->last_folder($folder);

            return $user;
            }
        , $self
        , $params
        );

    $user->update;
    return $user;
    }

# Sub: authenticate
#   Authenticates a user/password combination and retrieves the corresponding user.
# Parameters:
#   To be passed as an *anonymous* hash, like all other <Class::DBI> methods. Should have the following:
#   - username
#   - password
# Returns:
#   An <EP::Common::DBI::User> object, if password authenticates, nothing otherwise.
sub
authenticate
    {
    my $self = shift;
    my ($params) = @_;

    my ($user) = $self->search({ username => $params->{username} });
    return if not $user;

    my $crypted_password = unix_md5_crypt( $params->{password}, $user->salt );
    return $user if $crypted_password eq $user->password;
    }

# Sub: _before_create
#   Special create trigger to create user accounts, responsible for encrypting the password.
sub
_before_create
    {
    my $self = shift;

    $self->autoupdate(0);
    my $salt = join '', ('.', '/', 0..9, 'A'..'Z', 'a'..'z')[rand 64, rand 64];
    $self->password( unix_md5_crypt( $self->password, $salt ) );
    $self->salt( $salt );
    $self->autoupdate(1);
    }

1;
